package com.api.syh56.shengyunhui.service.impl;

import com.api.syh56.shengyunhui.common.BaseUserInfo;
import com.api.syh56.shengyunhui.common.Constants;
import com.api.syh56.shengyunhui.common.UserInfoEnu;
import com.api.syh56.shengyunhui.entity.*;
import com.api.syh56.shengyunhui.entity.vo.WAGParamVO;
import com.api.syh56.shengyunhui.exception.BaseException;
import com.api.syh56.shengyunhui.mapper.ShiperMapper;
import com.api.syh56.shengyunhui.mapper.DriverMapper;
import com.api.syh56.shengyunhui.mapper.WayBillMapper;
import com.api.syh56.shengyunhui.service.*;
import com.api.syh56.shengyunhui.util.CommonUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.openapi.sdk.service.DataExchangeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


@Service
@Slf4j
public class WayBillServiceImpl extends ServiceImpl<WayBillMapper,Waybill> implements WayBillService {
    @Autowired
    private WayBillMapper wayBillMapper;

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private TmpAddressService tmpAddressService;

    @Autowired
    private UserService userService;

    @Autowired
    private QuoteService quoteService;

    @Autowired
    private DriverMapper driverMapper;

    @Autowired
    private ShiperMapper shiperMapper;

    @Autowired
    private WechatPayService wechatPayService;

    @Autowired
    private SystemMessageService systemMessageService;


    @Override
    public Waybill addWaybill(Waybill waybill) {
        String id = BaseUserInfo.get(UserInfoEnu.id.getCode());
        waybill.setShiperId(Long.valueOf(id));
        waybill.setWaybillNumber(getWaybillNum());


        wayBillMapper.insert(waybill);
        return waybill;
    }



    public Waybill selectById(Long id) {
        Waybill waybill = wayBillMapper.selectById(id);
        if (waybill == null) {
            throw new BaseException("id不存在");
        }
        return waybill;
    }

    /**
     * 删除运单（连带删除其他关联表项goods tmpShipAddress tmpReceiveAddress）
     * @param id
     */
    @Override
    public void deleteWaybill(Long id) {
        Waybill waybill = wayBillMapper.selectById(id);
        Long goodsId = waybill.getGoodsId();
        Long shipAddressId = waybill.getShipAddressId();
        Long receiveAddressId = waybill.getReceiveAddressId();
        QueryWrapper<SystemMessage> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SystemMessage::getWaybillId,id);
        systemMessageService.remove(wrapper);
        goodsService.removeById(goodsId);
        tmpAddressService.removeById(shipAddressId);
        tmpAddressService.removeById(receiveAddressId);
        removeById(id);
    }

    @Override
    public void adminCancelWaybill(Long id){
        Waybill waybill = getById(id);
        //判断是否已付定金
        short waybillStatus = waybill.getWaybillStatus();
        Short[] legalStatus = {Constants.WaybillStatus.DEPOSIT_PAID};
        Set<Short> legalStatusSet = new HashSet<>(Arrays.asList(legalStatus));

        //退还定金
        if (legalStatusSet.contains(waybillStatus)){
            wechatPayService.wxpayrefund(id,Constants.Role.SUPERADMIN);
        }

        //运单状态、运输状态均改为 已取消
        waybill.setWaybillStatus(Constants.WaybillStatus.CANCELLED);
        waybill.setDeliveryStatus(Constants.DeliveryStatus.CANCELLED);
        saveOrUpdate(waybill);
    }

    @Override
    public void shipCancelWaybill(Long id){
        Waybill waybill = getById(id);
        //判断取消运单是否合法（未付定金）。已付定金需要取消运单，需要联系超级管理员
        short waybillStatus = waybill.getWaybillStatus();
        Short[] legalStatus = {Constants.WaybillStatus.AWAIT_QUOTE};
        Set<Short> legalStatusSet = new HashSet<>(Arrays.asList(legalStatus));

        //退还定金
        if (legalStatusSet.contains(waybillStatus)){
            //运单状态、运输状态均改为 已取消
            waybill.setWaybillStatus(Constants.WaybillStatus.CANCELLED);
            waybill.setDeliveryStatus(Constants.DeliveryStatus.CANCELLED);
            saveOrUpdate(waybill);
            QueryWrapper<SystemMessage> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(SystemMessage::getWaybillId,id);
            systemMessageService.remove(wrapper);
            //货主取消某一个运单后，将所有专线报价更新为未选中
            quoteService.cancelWaybillAndUpdateQuote(id);
        }else {
            throw new BaseException("不满足取消运单条件（已支付定金）");
        }

    }

    @Override
    public Map<String, String> shiperSettleWaybill(String code, Long waybillId, Long quoteId, String priceType, String platform) {
        Waybill waybill = getById(waybillId);
        short waybillStatus = waybill.getWaybillStatus();
        short deliveryStatus = waybill.getDeliveryStatus();
        //结算时不提供quoteId，需要从waybill中读取
        if(Objects.isNull(quoteId)){
            quoteId = waybill.getQuoteId();
        }
        Map<String, String> jsapiAndAppPrepayMap = new HashMap<>();
        //运输状态：已送达,运单状态：待结算
        if (Constants.WaybillStatus.AWAIT_SETTLEMENT.equals(waybillStatus)
                && Constants.DeliveryStatus.DELIVERED.equals(deliveryStatus)){
            jsapiAndAppPrepayMap = wechatPayService.jsapiAndAppPrepay(code, waybillId, quoteId, priceType, platform);
        }
        return jsapiAndAppPrepayMap;
    }


    @Override
    public WAGParamVO showOneInfo(Long id) {
        Waybill waybill = selectById(id);
        System.out.println(waybill.getId());

        Long goodsId = waybill.getGoodsId();
        Long driverId = waybill.getDriverId();
        Long shiperId = waybill.getShiperId();
        Long shipAddressId = waybill.getShipAddressId();
        Long receiveAddressId = waybill.getReceiveAddressId();

        //货物 用户信息（司机） 司机 临时发货地址 临时收货地址
        Goods goods = goodsService.selectById(goodsId);

        //尝试根据driverId查找对应司机用户（driverId可能为空值）  ”弃用“
        User driver_user = userService.selectById(driverId);
        Driver driver = new Driver();
        //如果运单还未完成报价确认，waybill的driver为空
        if(Objects.nonNull(driver_user)){
            QueryWrapper<Driver> driverQueryWrapper = new QueryWrapper<>();
            driverQueryWrapper.lambda().eq(Driver::getUid,driver_user.getId());
            driver = driverMapper.selectOne(driverQueryWrapper);
        }

        User shiper_user = userService.selectById(shiperId);
        Shiper shiper = new Shiper();
        if (Objects.nonNull(shiper_user)){
            QueryWrapper<Shiper> shiperQueryWrapper = new QueryWrapper<>();
            shiperQueryWrapper.lambda().eq(Shiper::getUid,shiper_user.getId());
            shiper = shiperMapper.selectOne(shiperQueryWrapper);
        }

        TmpAddress tmpshipAddress = tmpAddressService.selectById(shipAddressId);
        TmpAddress tmpreceiveAddress = tmpAddressService.selectById(receiveAddressId);

        WAGParamVO wagParamVO = WAGParamVO.builder()
                .waybill(waybill)
                .shiptmpAddress(tmpshipAddress)
                .receivetmpAddress(tmpreceiveAddress)
                .goods(goods)
                .driver_user(driver_user)
                .driver(driver)
                .shiper_user(shiper_user)
                .shiper(shiper)
                .build();
        return wagParamVO;
    }


    @Override
    public WAGParamVO convertToWAGParamVO(Long id) {
        return showOneInfo(id);
    }


    /**
     * 生成订单号（19位）：12位时间（精确到秒）+3位随机数+4位用户id
     */
    @Override
    public String getWaybillNum() {

        //时间（精确到毫秒）
        DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String localDate = LocalDateTime.now().format(ofPattern);
        //3位随机数
        String randomString = CommonUtil.getRandomString(3,"0123456789");
        //4位用户id
        int subStrLength = 4;
        String sUserId = BaseUserInfo.get(UserInfoEnu.id.getCode());
        int length = sUserId.length();
        String str = null;
        if (length >= subStrLength) {
            str = sUserId.substring(length - subStrLength, length);
        }
        String orderNum = localDate + str + randomString;
        log.info("订单号:{}", orderNum);
        return orderNum;

    }

    @Override
    public Map<String, List<WAGParamVO>> waybillRecentList(String yearmonth, Short status, Short role) {

        // 解析传入的年月字符串
        if (!yearmonth.matches("\\d{6}")) {
            throw new IllegalArgumentException("Invalid yearmonth format: " + yearmonth);
        }
        LocalDateTime startDateTime = LocalDateTime.of(
                Integer.parseInt(yearmonth.substring(0, 4)),
                Integer.parseInt(yearmonth.substring(4, 6)),
                1, 0, 0);

        // 计算三个月内的每个月的开始和结束时间
        Map<String, List<WAGParamVO>> result = new TreeMap<>(Comparator.reverseOrder());
        for (int month = 0; month < 3; month++) {
            LocalDateTime monthStart = startDateTime.minusMonths(month);
            LocalDateTime monthEnd = monthStart.plusMonths(1).withDayOfMonth(1);

            // 创建查询条件
            Long uid = Long.valueOf(BaseUserInfo.get(UserInfoEnu.id.getCode()));
            QueryWrapper<Waybill> wrapper = new QueryWrapper<>();
            wrapper.lambda()
                    .between(Waybill::getCreationTime, monthStart, monthEnd);
            if(Constants.Role.SHIPER.equals(role)){
                wrapper.lambda().eq(Waybill::getShiperId,uid)
                        .eq(Waybill::getWaybillStatus,status);
//                if (Constants.WaybillStatus.AWAIT_QUOTE.equals(status)) {
//                    System.out.println("status:"+status);
//                    wrapper.lambda()
//                            .eq(Waybill::getWaybillStatus,status)
//                            .or()
//                            .eq(Waybill::getWaybillStatus,Constants.WaybillStatus.WAIT_QUOTE);
//                }else {
//                    wrapper.lambda().eq(Waybill::getWaybillStatus,status);
//                }
            } else if (Constants.Role.DRIVER.equals(role)) {
                wrapper.lambda().eq(Waybill::getDriverId,uid)
                        .eq(Waybill::getDeliveryStatus,status);
            }
            wrapper.lambda().orderByDesc(Waybill::getCreationTime);

            // 调用服务层获取当前月的数据
            List<Waybill> waybills = list(wrapper);

            // 将Waybill列表转换为WAGParamVO列表
            ArrayList<WAGParamVO> WAGParamVOList = new ArrayList<>();
            waybills.forEach(waybill -> {
                WAGParamVO wagParamVO = convertToWAGParamVO(waybill.getId());
                WAGParamVOList.add(wagParamVO);
            });

            // 将结果放入Map中，key是年月字符串
            String monthKey = monthStart.getMonthValue() < 10 ? "0" + monthStart.getMonthValue() : "" + monthStart.getMonthValue();
            result.put(String.valueOf(monthStart).substring(0,7), WAGParamVOList);
        }
        // 打印结果，查看降序排列的键
        for (Map.Entry<String, List<WAGParamVO>> entry : result.entrySet()) {
            System.out.println("Key: " + entry.getKey());
        }
        return result;
    }

    @Override
    public Page<WAGParamVO> waybillRecentPage(Page page, Short status, Short role) {

            // 创建查询条件
            Long uid = Long.valueOf(BaseUserInfo.get(UserInfoEnu.id.getCode()));
            QueryWrapper<Waybill> wrapper = new QueryWrapper<>();
            wrapper.lambda()
                    .orderByDesc(Waybill::getCreationTime);
            if(Constants.Role.SHIPER.equals(role)){
                wrapper.lambda().eq(Waybill::getShiperId,uid)
                        .eq(Waybill::getWaybillStatus,status);
            } else if (Constants.Role.DRIVER.equals(role)) {
                wrapper.lambda().eq(Waybill::getDriverId,uid);
                //AWAIT_LOAD和TRANSPORTING合并获取
                if (Constants.DeliveryStatus.AWAIT_LOAD.equals(status) || Constants.DeliveryStatus.TRANSPORTING.equals(status)) {
                    wrapper.lambda().in(Waybill::getDeliveryStatus, Arrays.asList(Constants.DeliveryStatus.AWAIT_LOAD, Constants.DeliveryStatus.TRANSPORTING));
                }else {
                    wrapper.lambda().eq(Waybill::getDeliveryStatus,status);
                }

            }

            // 调用服务层获取当前月的数据
        Page<Waybill> waybillPage = page(page, wrapper);

        Page<WAGParamVO> wagParamVOPage = waybillPageToWAGParamVOPage(waybillPage);

        return wagParamVOPage;
    }



    @Override
    public Page<WAGParamVO> waybillPageToWAGParamVOPage(Page<Waybill> waybillPage) {
        Page<WAGParamVO> WAGParamVOPage = new Page<>();
// 复制分页信息
        WAGParamVOPage.setCurrent(waybillPage.getCurrent());
        WAGParamVOPage.setSize(waybillPage.getSize());
        WAGParamVOPage.setTotal(waybillPage.getTotal());
//        WAGParamVOPage.setPages(waybillPage.getPages());
//        WAGParamVOPage.setTotal(waybillPage.getTotal());
// 转换数据列表方法1（Stream API）
        List<WAGParamVO> waybilltestList = waybillPage.getRecords().stream()
                .map(waybill -> convertToWAGParamVO(waybill.getId())) // 使用方法引用进行转换
                .filter(wagParamVO -> wagParamVO.getShiper_user() != null) // 过滤 shiper_user 为 null 的记录
                .collect(Collectors.toList());
// 转换数据列表方法2
//                List<WAGParamVO> waybilltestList= new ArrayList<>();
//                waybillPage.getRecords().forEach(waybill -> {
//                    WAGParamVO wagParamVO = wayBillService.convertToWAGParamVO(waybill.getId());
//                    waybilltestList.add(wagParamVO);
//                });
// 将转换后的列表设置到新的 Page 对象中

        // 更新分页信息
        WAGParamVOPage.setPages((int) Math.ceil((double) waybilltestList.size() / waybillPage.getSize()));

        WAGParamVOPage.setRecords(waybilltestList);

        return WAGParamVOPage;
    }

    @Override
    @Transactional
    public void driverPushStatus(Waybill waybill, Short deliveryStatus) {

        //如果司机要推动的状态不是 [运输中、已送达] 则无效
        Short[] legalStatus = {Constants.DeliveryStatus.TRANSPORTING, Constants.DeliveryStatus.DELIVERED};
        Set<Short> legalStatusSet = new HashSet<>(Arrays.asList(legalStatus));
        if (!legalStatusSet.contains(deliveryStatus)){
            throw new BaseException("运输状态不合法");
        }



        short waybillStatus = waybill.getWaybillStatus();
        //WaybillStatus运单货主支付定金后，司机才可推动运输状态DeliveryStatus
        if (Constants.WaybillStatus.DEPOSIT_PAID.equals(waybillStatus)){
            waybill.setDeliveryStatus(deliveryStatus);
            if (deliveryStatus == Constants.DeliveryStatus.TRANSPORTING) {
                waybill.setShipTime(LocalDateTime.now());
            } else if (deliveryStatus == Constants.DeliveryStatus.DELIVERED) {
                waybill.setDeliveredTime(LocalDateTime.now());
            } else {
                throw new IllegalStateException("Unexpected value: " + deliveryStatus);
            }

        }else {
            throw new BaseException("货主未支付定金");
        }


        if (Constants.DeliveryStatus.DELIVERED.equals(deliveryStatus)){
            waybill.setWaybillStatus(Constants.WaybillStatus.AWAIT_SETTLEMENT);
            /**
             * 现付
             */
            if (Constants.PayMethod.PAY_NOW.equals(waybill.getPayMethod())){
                waybill.setWaybillStatus(Constants.WaybillStatus.SETTLED);
                waybill.setDeliveryStatus(Constants.DeliveryStatus.SETTLED);
            }
        }


        updateById(waybill);
    }

    @Override
    public Map<String, Object> waybillCarSearch(Waybill waybill) {
        TmpAddress start = tmpAddressService.getById(waybill.getShipAddressId());
        TmpAddress end = tmpAddressService.getById(waybill.getReceiveAddressId());
        String res = "";
        try {
            Map<String, String> map = new HashMap<String, String>(3);
            map.put("cid", "417a1452-00ff-4060-af52-f959d5b74374");
            map.put("srt", "f073c500-412e-4fbc-a10d-fe080b28ef8c");//私钥用于 SDK 生成签名，不会在请求中传输
            map.put("vnos", waybill.getCarNumber()+"_2"); //车牌号中间无空格
            map.put("timeNearby", "72");

            String shipaddresslocation = CommonUtil.getLocationWith7number(start.getAddressLocation());
            String receiveaddresslocation = CommonUtil.getLocationWith7number(end.getAddressLocation());
            map.put("startLonlat",shipaddresslocation);
            map.put("endLonlat",receiveaddresslocation);
            System.out.println(map);


            String url = "https://zhiyunopenapi.95155.com/save/apis/transTimeManageV3";
            DataExchangeService des = new DataExchangeService(5000, 8000);
            System.out.println("请求地址:"+url);
            // 通过 https 方式调用，此方法内部会使用私钥生成签名参数 sign,私钥不会发送
            res = des.postHttps(url, map);
            System.out.println(map);

            System.out.println("返回:"+ res);
        } catch (Exception e) {
            System.out.println("e:" + e.getMessage());
        }
        Gson gson = new Gson();
//        JsonObject jsonObject = gson.fromJson(res, JsonObject.class);
        JsonElement jsonElement = JsonParser.parseString(res);
        // 检查是否是JSON对象
        if (!jsonElement.isJsonObject()) {
            throw new RuntimeException("暂时无法规划路线");
        }
        JsonObject jsonObject = jsonElement.getAsJsonObject();
        // 检查键是否存在
        if (!jsonObject.has("result")) {
            throw new RuntimeException("暂时无法规划路线");
        }

        String adr = "";
        String lon = "";
        double lonNumType = 0.0;
        String lat = "";
        String runDistance = "";
        String remainDistance = "";
        LocalDateTime estimateArriveTime = null;
        double latNumType = 0.0;
        JsonObject firstVcl = null;
        JsonObject result = jsonObject.get("result").getAsJsonObject();
        if (result.has("firstVcl")) {
            firstVcl = result.get("firstVcl").getAsJsonObject();
        }else {
            throw new BaseException("暂未查询到车辆位置信息"+waybill.getCarNumber());
        }

        if (firstVcl.has("adr")) {
            adr = firstVcl.get("adr").getAsString();
        }
        if (firstVcl.has("lon")) {
            lon = firstVcl.get("lon").getAsString();
            lonNumType = Double.parseDouble(lon) / 600000.0;
        }
        if (firstVcl.has("lat")) {
            lat = firstVcl.get("lat").getAsString();
            latNumType = Double.parseDouble(lat) / 600000.0;
        }
        if (firstVcl.has("runDistance")){
            runDistance = firstVcl.get("runDistance").getAsString();
        }
        if (firstVcl.has("remainDistance")){
            remainDistance = firstVcl.get("remainDistance").getAsString();
        }
        if (firstVcl.has("estimateArriveTime")){
            String arriveTime = firstVcl.get("estimateArriveTime").getAsString();
            Instant instant = Instant.ofEpochMilli(Long.parseLong(arriveTime));
            estimateArriveTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        }
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();

        stringObjectHashMap.put("adr", adr);
        stringObjectHashMap.put("lon", lonNumType);
        stringObjectHashMap.put("lat", latNumType);
        stringObjectHashMap.put("runDistance",runDistance);
        stringObjectHashMap.put("remainDistance",remainDistance);
        stringObjectHashMap.put("estimateArriveTime",estimateArriveTime);
        return stringObjectHashMap;


    }

}
